home *** CD-ROM | disk | FTP | other *** search
/ Aminet 33 / Aminet 33 - October 1999.iso / Aminet / util / misc / VMM_src.lha / VMM / prepager.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-12-16  |  12.2 KB  |  475 lines

  1. #include <exec/types.h>
  2.  
  3. #ifdef __SASC
  4. #include <dos.h>
  5. #endif
  6.  
  7. #include "defs.h"
  8.  
  9. static char rcsid [] = "$Id: prepager.c,v 3.5 95/12/16 18:36:46 Martin_Apel Exp $";
  10.  
  11. /* The PrePager has two different tasks:
  12.  * 
  13.  * 1. Free  memory which should be freed by other tasks from inside a Forbid
  14.  *    / Disable.  A descriptor of the memory to be freed is put into a queue
  15.  *    and freed by the prepager the time Permit / Enable is called.
  16.  * 
  17.  * 2. Prevent  IO from or to the paging device using virtual memory which is
  18.  *    possibly not locked into memory.  Otherwise a deadlock would result.
  19.  */
  20.  
  21. PRIVATE struct IOStdReq       *CopiedReq;
  22. PRIVATE struct DosPacket      *CopiedPacket;
  23. PRIVATE struct MsgPort        *FileHandlerPort;
  24. PRIVATE struct Message*      (*OrigPktWait) (void);
  25. PRIVATE struct VMMsg          *PrePageMsg;
  26. PRIVATE UWORD                  ResetSignal;
  27. PRIVATE struct Message         QuitMsg;
  28. PRIVATE void                  *ResetHandlerData;
  29.  
  30. #define MIN(a,b) ((a)<(b)?(a):(b))
  31.  
  32. /********************************************************************/
  33.  
  34. PRIVATE void FreeForbiddenMem (void)
  35.  
  36. {
  37. struct ForbiddenFreeStruct *tmp_ffs;
  38. void *free_start;
  39. ULONG free_size;
  40.  
  41. while (VMToBeFreed != NULL)
  42.   {
  43.   Forbid ();
  44.   tmp_ffs = VMToBeFreed;
  45.   free_start = tmp_ffs->address;
  46.   free_size = tmp_ffs->size;
  47.   VMToBeFreed = tmp_ffs->NextFree;
  48.   tmp_ffs->NextFree = VMFreeRecycling;
  49.   VMFreeRecycling = tmp_ffs;
  50.   Permit ();
  51.   PRINT_DEB ("Freeing memory for other task", 0L);
  52.   FreeMem (free_start, free_size);
  53.   }
  54. }
  55.  
  56. /********************************************************************/
  57.  
  58. PRIVATE void PrepageIOStdReq (struct IOStdReq *req)
  59.  
  60. {
  61. ULONG Offset;
  62. BYTE Error;
  63. ULONG Actual;
  64. ULONG From;
  65. void *buffer;
  66. ULONG size;
  67.  
  68. PRINT_DEB ("PrepageIOStdReq called", 0L);
  69.  
  70. From = (ULONG)req->io_Data;
  71.  
  72. PRINT_DEB ("Current number of pageframes: %ld", NumPageFrames);
  73. PRINT_DEB ("Length of current request: %lx", req->io_Length);
  74.  
  75. Offset = req->io_Offset;
  76. Actual = 0L;
  77. Error = FALSE;
  78.  
  79. while (From < (ULONG)req->io_Data + req->io_Length)
  80.   {
  81.   /* Bug fix: If there are multiple units in the paging device, the
  82.    * Unit pointer must not be taken from OpenDevice, but be copied from
  83.    * the received request.
  84.    */
  85.   CopiedReq->io_Device  = req->io_Device;
  86.   CopiedReq->io_Unit    = req->io_Unit;
  87.  
  88.   size = (ULONG)req->io_Data + req->io_Length - From;
  89.   while ((buffer = AllocVec (size, MEMF_PUBLIC)) == NULL)
  90.     {
  91.     PRINT_DEB ("Request has to be split", 0L);
  92.     size = ALIGN_DOWN (size / 2, PagingDevParams.block_size);
  93.     if (size == 0)
  94.       {
  95.       PRINT_DEB ("Not enough memory to copy one block of data", 0L);
  96.       req->io_Error = IOERR_BADADDRESS;      /* This is not what it should */
  97.       req->io_Actual = 0;                    /* be, but there's no better */
  98.                                              /* error code available */
  99.       ReplyMsg ((struct Message*)req);
  100.       return;
  101.       }
  102.     }
  103.       
  104.   CopiedReq->io_Command = req->io_Command;
  105.   /* the quick bit has been cleared by the parthandler */
  106.   CopiedReq->io_Flags   = req->io_Flags | IOF_QUICK;
  107.   CopiedReq->io_Data    = buffer;
  108.   CopiedReq->io_Offset  = Offset;
  109.   CopiedReq->io_Length  = size;
  110.  
  111.   if (req->io_Command == CMD_WRITE)
  112.     {
  113.     if ((From & 0x3) == 0)         /* longword-aligned */
  114.       CopyMemQuick ((APTR)From, buffer, size);
  115.     else
  116.       CopyMem ((APTR)From, buffer, size);
  117.     }
  118.  
  119.   PRINT_DEB ("Sending request to device", 0L);
  120.   SendIO ((struct IORequest*)CopiedReq);
  121.   WaitIO ((struct IORequest*)CopiedReq);
  122.   PRINT_DEB ("Request finished", 0L);
  123.  
  124.   if (req->io_Command == CMD_READ)
  125.     {
  126.     if ((From & 0x3) == 0)         /* longword-aligned */
  127.       CopyMemQuick (buffer, (APTR)From, size);
  128.     else
  129.       CopyMem (buffer, (APTR)From, size);
  130.     }
  131.  
  132.   FreeVec (buffer);
  133.   Offset += size;
  134.   From += size;
  135.   Actual += CopiedReq->io_Actual;
  136.  
  137.   if (CopiedReq->io_Error)
  138.     {
  139.     Error = CopiedReq->io_Error;
  140.     PRINT_DEB ("IOStdReq returned with error %ld", (ULONG)Error);
  141.     PRINT_DEB ("Command was %ld", (ULONG)CopiedReq->io_Command);
  142.     break;
  143.     }
  144.   }
  145.  
  146. PRINT_DEB ("Done IO for requesting task", 0L);
  147.  
  148. req->io_Error = Error;
  149. req->io_Actual= Actual;
  150.  
  151. ReplyMsg ((struct Message*)req);
  152. }
  153.  
  154. /********************************************************************/
  155.  
  156. PRIVATE struct Message *GetPacket (void)
  157.  
  158. {
  159. struct Message *msg;
  160.  
  161. if (OrigPktWait != NULL)
  162.   msg = (*OrigPktWait) ();
  163. else
  164.   {
  165.   while ((msg = GetMsg (FileHandlerPort)) == NULL)
  166.     Wait (SIGF_DOS);
  167.   }
  168.  
  169. return (msg);
  170. }
  171.  
  172. /********************************************************************/
  173.  
  174. PRIVATE void PrepagePacket (struct DosPacket *packet);
  175.  
  176. PRIVATE struct Message *PktWaitPatch (void)
  177.  
  178. {
  179. struct Message *received_msg;
  180. struct DosPacket *received_packet;
  181.  
  182. for (;;)
  183.   {
  184.   received_msg = GetPacket ();
  185.   if (received_msg == &QuitMsg)
  186.     {
  187.     /* This is the quit msg. Deinstall myself */
  188.     PRINT_DEB ("Deinstalling PktWaitPatch", 0L);
  189.     FileHandlerProcess->pr_PktWait = (APTR)OrigPktWait;
  190.     return (NULL);
  191.     }
  192.  
  193.   received_packet = (struct DosPacket*)received_msg->mn_Node.ln_Name;
  194.  
  195.   switch (received_packet->dp_Action)
  196.     {
  197.     case ACTION_READ:
  198.     case ACTION_WRITE:
  199.       if ((received_packet->dp_Arg2 >= VirtAddrStart) &&
  200.           (received_packet->dp_Arg2 <  VirtAddrEnd))
  201.         {
  202.         PRINT_DEB ("Received R/W packet to VM", 0L);
  203.         PutMsg (PrePagerPort, received_msg);
  204.         break;
  205.         }
  206.     default:
  207.       return (received_msg);      
  208.     }
  209.   }
  210. }
  211.  
  212. /********************************************************************/
  213.  
  214. PRIVATE void PrepagePacket (struct DosPacket *packet)
  215.  
  216. {
  217. long Actual;
  218. long result;
  219. struct MsgPort *ReturnPort;
  220. ULONG From,
  221.       size;
  222. void *buffer;
  223.  
  224. /* dp_Arg1 contains pointer to Object
  225.  * dp_Arg2 is start of transfer
  226.  * dp_Arg3 is length of transfer
  227.  */
  228.  
  229. PRINT_DEB ("PrepagePacket called.", 0L);
  230. From = packet->dp_Arg2;
  231. Actual = 0;
  232.  
  233. while (From < packet->dp_Arg2 + packet->dp_Arg3)
  234.   {
  235.   size = (ULONG)packet->dp_Arg2 + packet->dp_Arg3 - From;
  236.   PRINT_DEB ("Allocating %ld bytes for tmp buffer", size);
  237.   while ((buffer = AllocVec (size, MEMF_PUBLIC)) == NULL)
  238.     {
  239.     PRINT_DEB ("Packet has to be split", 0L);
  240.     size = size / 2;
  241.     if (size == 0)
  242.       {
  243.       PRINT_DEB ("Not enough memory to copy data", 0L);
  244.       packet->dp_Res1 = -1;        /* Error marker */
  245.       packet->dp_Res2 = ERROR_NO_FREE_STORE;
  246.       ReturnPort = packet->dp_Port;
  247.       packet->dp_Port = FileHandlerPort;
  248.       PutMsg (ReturnPort, packet->dp_Link);
  249.       return;
  250.       }
  251.     }
  252.  
  253.   if (packet->dp_Action == ACTION_WRITE)
  254.     CopyMem ((APTR)From, buffer, size);
  255.  
  256.   CopiedPacket->dp_Action = packet->dp_Action;
  257.   CopiedPacket->dp_Arg1 = packet->dp_Arg1;
  258.   CopiedPacket->dp_Arg2 = (LONG)buffer;
  259.   CopiedPacket->dp_Arg3 = size;
  260.  
  261.   SendPkt (CopiedPacket, FileHandlerPort, &(PrePagerProcess->pr_MsgPort));
  262.   WaitPkt ();
  263.   result = CopiedPacket->dp_Res1;
  264.  
  265.   if (packet->dp_Action == ACTION_READ)
  266.     CopyMem (buffer, (APTR)From, result);    /* result contains the number */
  267.                                              /* of bytes read */
  268.  
  269.   FreeVec (buffer);
  270.  
  271.   From += size;
  272.   Actual += result;
  273.  
  274.   if (result <= 0)
  275.     break;
  276.   }
  277.  
  278. PRINT_DEB ("Done IO for requesting task", 0L);
  279.  
  280. packet->dp_Res1 = Actual;
  281. packet->dp_Res2 = CopiedPacket->dp_Res2;
  282. ReturnPort = packet->dp_Port;
  283. packet->dp_Port = FileHandlerPort;
  284. PutMsg (ReturnPort, packet->dp_Link);
  285. }
  286.  
  287. /*********************************************************************/
  288.  
  289. PRIVATE void ResetHandler (void)
  290.  
  291. {
  292. PRINT_DEB ("Sending reset signal to prepager", 0L);
  293. Signal (PrePagerTask, 1L << ResetSignal);
  294. }
  295.  
  296. /********************************************************************/
  297.  
  298. PRIVATE int InitPrePager (void)
  299.  
  300. {
  301. /* 16 signals per task are guaranteed, so the following four lines
  302.  * can't fail
  303.  */
  304.  
  305. PrePagerQuitSignal = AllocSignal (-1L);
  306. FreeVMSignal       = AllocSignal (-1L);
  307. ResetSignal        = AllocSignal (-1L);
  308.  
  309. if ((PrePagerPort = CreateMsgPort ()) == NULL) 
  310.   return (ERR_NOT_ENOUGH_MEM);
  311.  
  312. if ((CopiedReq = CreateIORequest (PrePagerPort, sizeof (struct IOStdReq))) 
  313.                     == NULL)
  314.   return (ERR_NOT_ENOUGH_MEM);
  315.  
  316. PRINT_DEB ("Patching BeginIO", 0L);
  317.  
  318. OrigBeginIO = (void (*) ()) SetFunction ((struct Library*)PagingDevParams.device, 
  319.                                  DEV_BEGINIO, (ULONG (*) ()) PartHandler);
  320.  
  321. PRINT_DEB ("BeginIO successfully patched", 0L);
  322.  
  323. VMToBeFreed = NULL;
  324. VMFreeRecycling = NULL;
  325.  
  326. if ((PrePageMsg = DoOrigAllocMem (sizeof (struct VMMsg), MEMF_PUBLIC)) == NULL)
  327.   return (ERR_NOT_ENOUGH_MEM);
  328.  
  329. PRINT_DEB ("Allocated PrePageMsg", 0L);
  330.  
  331. if (CurrentConfig.PageDev == PD_FILE)
  332.   {
  333.   if ((CopiedPacket = AllocDosObject (DOS_STDPKT, NULL)) == NULL)
  334.     {
  335.     PRINT_DEB ("No mem for CopiedPacket", 0L);
  336.     return (ERR_NOT_ENOUGH_MEM);
  337.     }
  338.  
  339.   FileHandlerProcess = (struct Process*)PagingDevParams.SysTask;
  340.   FileHandlerPort    = &(FileHandlerProcess->pr_MsgPort);
  341.  
  342.   /* Install PktWaitPatch */
  343.   OrigPktWait = (struct Message* (*) ())FileHandlerProcess->pr_PktWait;
  344.   FileHandlerProcess->pr_PktWait = (APTR)PktWaitPatch;
  345.   }
  346.  
  347. if ((ResetHandlerData = InstallResetHandler (ResetHandler, -32L)) == NULL)
  348.   PRINT_DEB ("Couldn't install reset handler", 0L);
  349.  
  350. PRINT_DEB ("Installed reset handler", 0L);
  351. return (SUCCESS);
  352. }
  353.  
  354. /********************************************************************/
  355.  
  356. PRIVATE void Cleanup_PrePager (void)
  357.  
  358. {
  359. struct ForbiddenFreeStruct *tmp_ffs;
  360.  
  361. RemoveResetHandler (ResetHandlerData);
  362.  
  363. if (CurrentConfig.PageDev == PD_FILE)
  364.   {
  365.   PRINT_DEB ("Requesting PktWaitPatch to quit", 0L);
  366.   PutMsg (FileHandlerPort, &QuitMsg);
  367.   while (FileHandlerProcess->pr_PktWait != (APTR)OrigPktWait)
  368.     Delay (1L);
  369.  
  370.   FreeDosObject (DOS_STDPKT, CopiedPacket);
  371.   }
  372.  
  373. if (PrePageMsg != NULL)
  374.   FreeMem (PrePageMsg, sizeof (struct VMMsg));
  375.  
  376. while ((tmp_ffs = VMFreeRecycling) != NULL)
  377.   {
  378.   VMFreeRecycling = tmp_ffs->NextFree;
  379.   FreeMem (tmp_ffs, sizeof (struct ForbiddenFreeStruct));
  380.   }
  381.  
  382. if (OrigBeginIO != NULL)
  383.   SetFunction ((struct Library*)PagingDevParams.device, 
  384.                                  DEV_BEGINIO, (ULONG (*) ()) OrigBeginIO);
  385.  
  386. if (CopiedReq != NULL)
  387.   DeleteIORequest ((struct IORequest*)CopiedReq);
  388.  
  389. if (PrePagerPort != NULL)
  390.   DeleteMsgPort (PrePagerPort);
  391.  
  392. FreeSignal ((ULONG) PrePagerQuitSignal);
  393. FreeSignal ((ULONG) FreeVMSignal);
  394. FreeSignal ((ULONG) ResetSignal);
  395. }
  396.  
  397. /********************************************************************/
  398.  
  399. void PrePager (void)
  400.  
  401. {
  402. ULONG WaitMask;
  403. ULONG ReceivedSignals;
  404. BOOL quit = FALSE;
  405. struct VMMsg *InitMsg;
  406. struct Message *PrePageMsg;
  407. int rc;
  408.  
  409. if ((rc = InitPrePager ()) != SUCCESS)
  410.   {
  411.   PRINT_DEB ("Init failed", 0L);
  412.   InitError (rc);
  413.   Cleanup_PrePager ();
  414.   Signal ((struct Task*)VM_ManagerProcess, 1L << InitPort->mp_SigBit);
  415.   return;
  416.   }
  417.  
  418. PRINT_DEB ("Init successful", 0L);
  419. /* Tell VM_Manager that the PrePager has been initialized correctly */
  420. if ((InitMsg = DoOrigAllocMem (sizeof (struct VMMsg), MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
  421.   {
  422.   PRINT_DEB ("PrePager: Not enough memory for init msg", 0L);
  423.   InitError (ERR_NOT_ENOUGH_MEM);
  424.   Cleanup_PrePager ();
  425.   Signal ((struct Task*)VM_ManagerProcess, 1L << InitPort->mp_SigBit);
  426.   return;
  427.   }
  428.  
  429. InitMsg->VMSender = FindTask (NULL);
  430. InitMsg->VMCommand = VMCMD_InitReady;
  431. InitMsg->ReplySignal = NULL;       /* Let VM_Manager free this */
  432. PutMsg (InitPort, (struct Message*)InitMsg);
  433.  
  434. WaitMask = (1L << PrePagerPort->mp_SigBit) | 
  435.            (1L << PrePagerQuitSignal)      |
  436.            (1L << FreeVMSignal)            |
  437.            (1L << ResetSignal);
  438.  
  439. while (!quit)
  440.   {
  441.   PRINT_DEB ("Waiting for signals", 0L);
  442.   ReceivedSignals = Wait (WaitMask);
  443.   PRINT_DEB ("Received signals: %lx", ReceivedSignals);
  444.  
  445.   if (ReceivedSignals & (1L << PrePagerPort->mp_SigBit))
  446.     {
  447.     while ((PrePageMsg = GetMsg (PrePagerPort)) != NULL)
  448.       {
  449.       if ((TypeOfMem (PrePageMsg->mn_Node.ln_Name) != 0) &&
  450.           (((struct DosPacket*)(PrePageMsg->mn_Node.ln_Name))->dp_Link == 
  451.                                                            PrePageMsg))
  452.         PrepagePacket ((struct DosPacket*)PrePageMsg->mn_Node.ln_Name);
  453.       else
  454.         PrepageIOStdReq ((struct IOStdReq*)PrePageMsg);
  455.       }
  456.     }
  457.  
  458.   if (ReceivedSignals & (1L << FreeVMSignal))
  459.     FreeForbiddenMem ();
  460.  
  461.   if (ReceivedSignals & (1L << PrePagerQuitSignal))
  462.     quit = TRUE;
  463.  
  464.   if (ReceivedSignals & (1L << ResetSignal))
  465.     {
  466.     PRINT_DEB ("Received reset signal", 0L);
  467.     ResetHandlerDone (ResetHandlerData);
  468.     WaitMask = (1L << FreeVMSignal);
  469.     }
  470.   }
  471.  
  472. Cleanup_PrePager ();
  473. PRINT_DEB ("Exiting", 0L);
  474. }
  475.